package com.alan.search.dao;

import com.alan.search.vo.EsPage;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * elasticsearch 基础DAO
 *
 * @author shiml
 * @date 2021/1/26 3:24 下午
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class BaseElasticDao {

    private final RestHighLevelClient restHighLevelClient;

    private static ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }

    /**
     * 获取存在的索引
     *
     * @param indices
     * @return
     */
    public String[] getExistIndices(String[] indices) {

        List<String> existIndexList = new ArrayList<>();
        for (String index : indices) {
            GetIndexRequest indexRequest = new GetIndexRequest(index);
            try {
                log.debug("判断索引存在查询开始{}", System.currentTimeMillis());
                boolean exists = restHighLevelClient.indices().exists(indexRequest, RequestOptions.DEFAULT);
                log.debug("判断索引存在查询结束{}", System.currentTimeMillis());
                if (exists) {
                    existIndexList.add(index);
                }
            } catch (IOException e) {
                log.error("judge index exist fail,indexRequest = [{}],message = [{}]", indexRequest.toString(), e.getMessage());
            }
        }
        return existIndexList.toArray(new String[0]);
    }

    /**
     * 获取存在的索引
     *
     * @param index
     * @return
     */
    public String[] getExistIndices(String index) {

        List<String> existIndexList = new ArrayList<>();
        GetIndexRequest indexRequest = new GetIndexRequest(index);
        try {
            log.debug("判断索引存在查询开始{}", System.currentTimeMillis());
            boolean exists = restHighLevelClient.indices().exists(indexRequest, RequestOptions.DEFAULT);
            log.debug("判断索引存在查询结束{}", System.currentTimeMillis());
            if (exists) {
                existIndexList.add(index);
            }
        } catch (IOException e) {
            log.error("judge index exist fail,indexRequest = [{}],message = [{}]", indexRequest.toString(), e.getMessage());
        }
        return existIndexList.toArray(new String[0]);
    }

    /**
     * @param searchRequest 查询参数
     * @param c             结果类对象
     * @return EsPage
     * @throws
     */
    public <T> EsPage<T> search(SearchRequest searchRequest, Class<T> c) {

        try {

            log.info("searchLogPage: DSL = \n {}", searchRequest.toString());

            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            SearchHit[] hits = response.getHits().getHits();

            List<T> res = new ArrayList<>(hits.length);
            for (SearchHit hit : hits) {
                res.add(objectMapper.readValue(hit.getSourceAsString(), c));
            }

            EsPage esPage = new EsPage(searchRequest.source().from(), searchRequest.source().size());
            esPage.setRecords(res);
            esPage.setTotal(Long.valueOf(response.getHits().getTotalHits().value).intValue());

            return esPage;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param idxName index
     * @param builder 查询参数
     * @param c       结果类对象
     * @return java.util.List<T>
     * @throws
     * @author WCNGS@QQ.COM
     * @See
     * @date 2019/10/17 17:14
     * @since
     */
    public <T> List<T> search(String[] idxName, SearchSourceBuilder builder, Class<T> c) {

        if (idxName.length == 0) {
            return new ArrayList<>(0);
        }

        SearchRequest request = new SearchRequest(idxName);
        request.source(builder);
        try {
            log.info("DSL:\n{}", builder.toString());
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            List<T> res = new ArrayList<>(hits.length);
            for (SearchHit hit : hits) {
                res.add(JSON.parseObject(hit.getSourceAsString(), c));
            }
            return res;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param request 查询参数
     * @param c       结果类对象
     * @return java.util.List<T>
     * @throws
     * @author WCNGS@QQ.COM
     * @See
     * @date 2019/10/17 17:14
     * @since
     */
    public <T> List<T> listSearch(SearchRequest request, Class<T> c) {

        try {
            log.info("DSL:\n{}", request.toString());
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            SearchHit[] hits = response.getHits().getHits();
            List<T> res = new ArrayList<>(hits.length);
            for (SearchHit hit : hits) {
                res.add(JSON.parseObject(hit.getSourceAsString(), c));
            }
            return res;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}